package com.taglab.chic.config;

import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.PropertyResourceConfigurer;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import static org.springframework.beans.factory.config.PropertyPlaceholderConfigurer.SYSTEM_PROPERTIES_MODE_FALLBACK;
import org.springframework.beans.BeansException;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PropertiesLoaderSupport;
import org.springframework.core.PriorityOrdered;
import org.springframework.core.Ordered;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Properties;

/**
 * 
 * @author Markus Kobler
 */
public class ConfigurationPropertiesFactoryBean extends PropertiesLoaderSupport  
  implements FactoryBean, InitializingBean, BeanFactoryPostProcessor, PriorityOrdered {

  private Properties propertiesInstance;
  private Resource overrideLocation;
  private boolean printProperties = true;

  private PropertyResourceConfigurer postProcessor = new PropertyPlaceholderConfigurer();

  public ConfigurationPropertiesFactoryBean() {
    setFileEncoding("UTF-8");
  }

  public void setOverrideLocation(Resource overrideLocation) {
    this.overrideLocation = overrideLocation;
  }

  public void setPrintProperties(boolean printProperties) {
    this.printProperties = printProperties;
  }

  public boolean isSingleton() {
    return true;
  }

  public Class getObjectType() {
    return Properties.class;
  }

  public void afterPropertiesSet() throws Exception {

    propertiesInstance = mergeProperties();

    Properties defaultProperties= null;

    if( printProperties ) {
      defaultProperties = new Properties();
      defaultProperties.putAll(propertiesInstance);
    }

    if( overrideLocation == null ) {

      logger.warn("Override Location not set");

    } if( overrideLocation.exists() ) {

      setIgnoreResourceNotFound(true);
      setLocation(overrideLocation);
      loadProperties(propertiesInstance);

    } else {

      logger.info("Overrides "+overrideLocation+" not found");

    }

    if( printProperties ) {
      
      @SuppressWarnings("unchecked")
      List<String> keys = new ArrayList(propertiesInstance.keySet());
      
      Collections.sort(keys);

      for (String key : keys) {

        String value = propertiesInstance.getProperty(key);
        String defaultValue = defaultProperties.getProperty(key);

        String type = "";
        if( defaultValue == null ) {
          type = " (+)";
        } else if( !value.equals(defaultValue) ) {
          type = " (*)";
        }
        
        logger.info(key + " = " + value + type);
      }
    }

    if( postProcessor != null ) {
      postProcessor.setProperties(propertiesInstance);
    }
    if( postProcessor instanceof PropertyPlaceholderConfigurer ) {
      ((PropertyPlaceholderConfigurer)postProcessor).setSystemPropertiesMode(SYSTEM_PROPERTIES_MODE_FALLBACK);
    }
    
  }

  public Object getObject() throws Exception {
    return propertiesInstance;
  }


  public int getOrder() {
    return postProcessor != null ? postProcessor.getOrder() : Ordered.LOWEST_PRECEDENCE;
  }


  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    if( postProcessor != null ) {
      postProcessor.postProcessBeanFactory(beanFactory);
    }
  }
}
